/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package analiseSintatica.Regras.Expressoes;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.ReconhecerTerminais;
import analiseSintatica.Regras.Regra;
import analiseSintatica.estruturadados.ErroSintatico;
import analiseSintatica.estruturadados.NoArvore;

import java.util.LinkedList;

/**
 *
 * @author matheus
 */
public class RegraUnarioPrefixa extends Regra {

    protected static Regra instancia;

    protected String estrutura = "<unario_posfixa> | <op_incremento> identificador | <op_unario> identificador";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraUnarioPrefixa() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraUnarioPrefixa getInstance() {
        if (instancia == null) {
            instancia = new RegraUnarioPrefixa();
        }
        return (RegraUnarioPrefixa) instancia;
    }

    @Override
    public NoArvore analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {
        ErroSintaticoException erros = new ErroSintaticoException();
        
        NoArvore naoterminalunarioprefixa = new NoArvore("<unario_prefixa>", false);

        if (RegraUnarioPosfixa.getInstance().getPrimeiro().contains(listaTokens.getFirst().getToken())||
                RegraUnarioPosfixa.getInstance().getPrimeiro().contains(listaTokens.getFirst().getLexema())) {

            try{
                naoterminalunarioprefixa.adicionaFilho(RegraUnarioPosfixa.getInstance().analisar(listaTokens));
            }catch(ErroSintaticoException e){
                while (e.size() != 0) {
                    erros.addErros(e.getErros());
                }
            }
            
        }else if(RegraOpIncremento.getInstance().getPrimeiro().contains(listaTokens.getFirst().getLexema())||
                RegraOpIncremento.getInstance().getPrimeiro().contains(listaTokens.getFirst().getToken())){
            try{
                naoterminalunarioprefixa.adicionaFilho(RegraOpIncremento.getInstance().analisar(listaTokens));
            }catch(ErroSintaticoException e){
                while (e.size() != 0) {
                    erros.addErros(e.getErros());
                }
            }

            try{
                naoterminalunarioprefixa.adicionaFilho(reconheceToken(listaTokens, "identificador",estrutura));
            }catch(ErroSintaticoException e){
                ErroSintatico erro = e.getErros();
                erro.setCorreto(estrutura);
                erros.addErros(erro);
                LinkedList<String> sincronizacao = getSeguinte();
                LinkedList<String> id = new LinkedList<String>();
                id.add("identificador");
                sincronizacao = getUniao(sincronizacao, id);
                while (!listaContem(sincronizacao, listaTokens.getFirst())) {
                    erros.addErros("Token " + listaTokens.getFirst().getToken() + " nao permitido", estrutura, listaTokens.getFirst().getLinha());
                    listaTokens.removeFirst();
                }
                if (listaTokens.getFirst().getToken().equals("delimitador")) {
                    listaTokens.removeFirst();
                }
            }
            
        }else{
            try{
                naoterminalunarioprefixa.adicionaFilho(RegraOpUnario.getInstance().analisar(listaTokens));
            }catch(ErroSintaticoException e){
                while (e.size() != 0) {
                    erros.addErros(e.getErros());
                }
            }

            try{
                naoterminalunarioprefixa.adicionaFilho(reconheceToken(listaTokens, "identificador",estrutura));
            }catch(ErroSintaticoException e){
                ErroSintatico erro = e.getErros();
                erro.setCorreto(estrutura);
                erros.addErros(erro);
                LinkedList<String> sincronizacao = getSeguinte();
                LinkedList<String> id = new LinkedList<String>();
                id.add("identificador");
                sincronizacao = getUniao(sincronizacao, id);
                while (!listaContem(sincronizacao, listaTokens.getFirst())) {
                    erros.addErros("Token " + listaTokens.getFirst().getToken() + " nao permitido", estrutura, listaTokens.getFirst().getLinha());
                    listaTokens.removeFirst();
                }
                if (listaTokens.getFirst().getToken().equals("delimitador")) {
                    listaTokens.removeFirst();
                }
            }
        }

        if(erros.size() != 0)
            throw erros;
        return naoterminalunarioprefixa;
    }



    protected void setPrimeiro() {
        /*P(unario_prefixa) = P(unario_posfixa) U P(op_incremento) U P(op_unario)
         ->P(unario_prefixa)= {identificador, "(", numeroInteiro , numeroFlutuante
         , charconst, '++', '--', '&', '*'}*/
       /* primeiro = RegraUnarioPosfixa.getInstance().getPrimeiro();
        primeiro = getUniao(primeiro, RegraOpIncremento.getInstance().getPrimeiro());
        primeiro = getUniao(primeiro, RegraOpUnario.getInstance().getPrimeiro());*/
        this.primeiro.add("identificador");
        this.primeiro.add("(");
        this.primeiro.add("numeroInteiro");
        this.primeiro.add("numeroFlutuante");
        this.primeiro.add("charconst");
        this.primeiro.add("++");
        this.primeiro.add("--");
        this.primeiro.add("&");
        this.primeiro.add("*");

    }

    protected void setSeguinte() {
        // S(unario_prefixa) = S(cast)
      //  seguinte = RegraCast.getInstance().getSeguinte();
        seguinte.add("(");
        seguinte.add("{");
        seguinte.add("identificador");
        seguinte.add("numeroInteiro");
        seguinte.add("numeroFlutuante");
        seguinte.add("charconst");
        seguinte.add("++");
        seguinte.add("--");
        seguinte.add("&");
        seguinte.add("*");
        seguinte.add("+");
        seguinte.add("-");
        seguinte.add("<");
        seguinte.add("<=");
        seguinte.add(">");
        seguinte.add(">=");
        seguinte.add("==");
        seguinte.add("!=");
        seguinte.add("&&");
        seguinte.add(";");
        seguinte.add(",");
        seguinte.add("}");
        seguinte.add(")");
    }
}
